package vip.liux.front.application.serviceimpl.paymeny;

import jakarta.persistence.EntityNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import vip.liux.front.application.service.payment.*;
import vip.liux.front.domain.models.payment.IPaymentGateway;
import vip.liux.front.domain.models.payment.IPaymentRequestRepository;
import vip.liux.front.domain.models.payment.PaymentRequest;
import vip.liux.front.domain.shared.payment.PayGateway;
import vip.liux.front.domain.shared.payment.PaymentRequestCompletedEto;
import vip.liux.front.infrastructure.code.BizCodeGenerator;

import java.util.Map;
import java.util.Optional;

@Service
public class PaymentRequestAppService implements IPaymentRequestAppService {

    private static final Logger log = LoggerFactory.getLogger(PaymentRequestAppService.class);
    private final BizCodeGenerator codeGenerator;
    private final PluginRegistry<IPaymentGateway, PayGateway> paymentGatewayRegistry;
    private final IPaymentRequestRepository paymentRequestRepository;

    public PaymentRequestAppService(BizCodeGenerator codeGenerator, PluginRegistry<IPaymentGateway, PayGateway> paymentGatewayRegistry, IPaymentRequestRepository paymentRequestRepository) {
        this.codeGenerator = codeGenerator;
        this.paymentGatewayRegistry = paymentGatewayRegistry;
        this.paymentRequestRepository = paymentRequestRepository;
    }

    /**
     * 创建支付请求.
     *
     * @param input 输入参数
     * @return 支付请求
     */
    @Override
    @Transactional
    public PaymentRequestWithDetailsDto create(PaymentRequestCreateDto input) {
        PaymentRequest request = new PaymentRequest(codeGenerator.generatePaymentRequestCode("PAYMENT_REQUEST"));

        for (Map.Entry<String, Object> keyValuePair : input.getExtraProperties().entrySet()) {
            request.getExtraProperties().put(keyValuePair.getKey(), keyValuePair.getValue());
        }

        for (PaymentRequestProductCreateDto product : input.getProducts()) {
            request.addProduct(product.getCode(), product.getName(), product.getUnitPrice(), product.getCount(), product.getTotalPrice(), product.getExtraProperties());
        }

        PaymentRequest result = paymentRequestRepository.save(request);

        return getPaymentRequestWithDetailsDto(result);
    }

    /**
     * 获取支付请求.
     *
     * @param id 支付请求ID
     * @return 支付请求
     */
    @Override
    public PaymentRequestWithDetailsDto get(String id) {
        PaymentRequest request = paymentRequestRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Payment request not found"));
        return getPaymentRequestWithDetailsDto(request);
    }

    /**
     * 完成支付请求.
     *
     * @param input 输入参数
     * @return 支付请求
     */
    @Override
    public PaymentRequestWithDetailsDto complete(CompletePaymentRequestDto input) {
        PaymentRequest request = paymentRequestRepository.findById(input.getId()).orElseThrow(() -> new EntityNotFoundException("Payment request not found"));
        Optional<IPaymentGateway> optional = paymentGatewayRegistry.getPluginFor(PayGateway.valueOf(request.getGateway()));

        if (optional.isEmpty()) {
            throw new RuntimeException("Invalid payment gateway type.");
        }

        if (!optional.get().isValid(request, input.getExtraProperties())) {
            throw new RuntimeException("Your payment is not valid.");
        }

        for (Map.Entry<String, Object> keyValuePair : input.getExtraProperties().entrySet()) {
            request.getExtraProperties().put(keyValuePair.getKey(), keyValuePair.getValue());
        }

        request.setGateway(input.getGateway());
        request.complete(true);

        PaymentRequest result = paymentRequestRepository.save(request);
        return getPaymentRequestWithDetailsDto(result);
    }

    /**
     * 设置支付请求的货币.
     *
     * @param input 输入参数
     * @return 支付请求
     */
    @Override
    public PaymentRequestWithDetailsDto setCurrency(SetPaymentRequestCurrencyDto input) {
        PaymentRequest request = paymentRequestRepository.findById(input.id()).orElseThrow(() -> new EntityNotFoundException("Payment request not found"));
        request.setCurrency(input.currency());

        paymentRequestRepository.save(request);
        return getPaymentRequestWithDetailsDto(request);
    }

    private PaymentRequestWithDetailsDto getPaymentRequestWithDetailsDto(PaymentRequest request) {
        return AutoMapperProfile.INSTANCE.toDto(request);
    }

    //接受User发出的类型为UserSaveEvent的DomainEvents事件
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void event(PaymentRequestCompletedEto event) {
        log.info("PaymentRequestCompletedEto: {}", event);
    }
}
